package com.boot.common.utils;

import com.boot.common.constants.Constants;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

/**
 * @author Cheng JiYe
 * @description: 时间转换工具类
 * @date 2020/10/2 1:08
 */
public class DateUtils {

  /**
   * 获取当前系统日期
   *
   * @return 系统当前时间
   */
  public static Date getCurrentDate() {
    return new Date();
  }

  /**
   * 得到当前时间
   *
   * @return
   */
  public static Long getCurrentTimeLong() {
    return System.currentTimeMillis();
  }

  public static void main(String[] args) {
    System.out.println(getCurrentTimeLong());
  }

  /**
   * 获取当前日期，格式：yyyy-MM-dd
   *
   * @return
   */
  public static String getCurrentDateString() {
    // 设置日期格式
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    return df.format(new Date());
  }

  /**
   * @param date 时间
   * @param pattern 日期格式
   * @return
   */
  private static String getDateToString(Date date, String pattern) {
    if (StringUtils.isBlank(date) || StringUtils.isBlank(pattern)) {
      return "";
    }
    // 设置字符串格式
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
    return simpleDateFormat.format(date);
  }

  /**
   * 转换指定时间格式
   *
   * @param date
   * @param pattern
   * @return
   */
  public static String getDateToStringStart(Date date, String pattern) {
    return DateUtils.getDateToString(date, pattern);
  }

  /**
   * 获取本周第1天
   *
   * <p>每星期第一天为：星期1，最后一天为星期日
   *
   * @return yyyy-mm-dd
   */
  public static String getMondayOfThisWeek() {
    return LocalDate.now().plusWeeks(0).with(DayOfWeek.MONDAY).toString();
  }

  /**
   * 获取本周最后1天 每星期第一天为：星期一，最后一天为星期日
   *
   * @return yyyy-mm-dd
   */
  public static String getWeeklastday() {
    return LocalDate.now().plusWeeks(0).with(DayOfWeek.SUNDAY).toString();
  }

  /**
   * 获取上周第一天的时间 yyyy-mm-dd 每星期第一天为：星期一，最后一天为星期日
   *
   * @return yyyy-mm-dd
   */
  public static String getLastWeekFirstDay() {
    return LocalDate.now().plusWeeks(-1).with(DayOfWeek.MONDAY).toString();
  }

  /**
   * 获取上周最后一天的时间 yyyy-mm-dd 每星期第一天为：星期一，最后一天为星期日
   *
   * @return yyyy-mm-dd
   */
  public static String getLastWeekEndDay() {
    return LocalDate.now().plusWeeks(-1).with(DayOfWeek.SUNDAY).toString();
  }

  /**
   * 获取去年的本周的开始时间
   *
   * @return yyyy-mm-dd
   */
  public static String getLastYearThisWeekFirst() {
    return LocalDate.now().minusYears(1).with(DayOfWeek.MONDAY).toString();
  }

  /**
   * 获取去年的本周的结束时间
   *
   * @return yyyy-mm-dd
   */
  public static String getLastYearThisWeekEnd() {
    return LocalDate.now().minusYears(1).with(DayOfWeek.SUNDAY).toString();
  }

  /**
   * 获取本月第一天
   *
   * @return yyyy-mm-dd
   */
  public static String getThisMonthFirstDay() {
    return LocalDate.now().plusMonths(0).with(TemporalAdjusters.firstDayOfMonth()).toString();
  }

  /**
   * 获取本月最后一天
   *
   * @return yyyy-mm-dd
   */
  public static String getThisMonthEndDay() {
    return LocalDate.now().minusMonths(0).with(TemporalAdjusters.lastDayOfMonth()).toString();
  }

  /**
   * 获取上月第一天
   *
   * @return yyyy-mm-dd
   */
  public static String getLastMonthFirstDay() {
    return LocalDate.now().plusMonths(-1).with(TemporalAdjusters.firstDayOfMonth()).toString();
  }

  /**
   * 获取本月天数
   *
   * @return yyyy-mm-dd
   */
  public static int getThisMonthDayCount() {
    return LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
  }

  /**
   * 获取上月天数
   *
   * @return yyyy-mm-dd
   */
  public static int getLastMonthDayCount() {
    return LocalDate.now().plusMonths(-1).with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
  }

  /**
   * 获取上月最后一天 DateUtils
   *
   * @return yyyy-mm-dd
   */
  public static String getLastMonthEndDay() {
    return LocalDate.now().minusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).toString();
  }

  /**
   * 获取去年本月的开始时间
   *
   * @return yyyy-mm-dd
   */
  public static String getLastYearMonthStartDay() {
    return LocalDate.now().plusYears(-1).with(TemporalAdjusters.firstDayOfMonth()).toString();
  }

  /**
   * 获取去年本月的结束时间
   *
   * @return yyyy-mm-dd
   */
  public static String getLastYearMonthEndDay() {
    return LocalDate.now().plusYears(-1).with(TemporalAdjusters.lastDayOfMonth()).toString();
  }

  /**
   * 获取本季第一天
   *
   * @return yyyy-mm-dd
   */
  public static String getThisQuarterFirstDay() {
    LocalDate inputDate = LocalDate.parse(getCurrentDateString());
    Month month = inputDate.getMonth();
    Month firstMonthOfQuarter = month.firstMonthOfQuarter();
    LocalDate localDate = LocalDate.of(inputDate.getYear(), firstMonthOfQuarter, 1);
    return localDate.toString();
  }

  /**
   * 获取本季度最后一天
   *
   * @return yyyy-mm-dd
   */
  public static String getThisQuarterEndDay() {
    LocalDate inputDate = LocalDate.parse(getCurrentDateString());
    Month month = inputDate.getMonth();
    Month firstMonthOfQuarter = month.firstMonthOfQuarter();
    Month endMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
    LocalDate localDate =
        LocalDate.of(
            inputDate.getYear(),
            endMonthOfQuarter,
            endMonthOfQuarter.length(inputDate.isLeapYear()));
    return localDate.toString();
  }

  /**
   * 获取上季度第一天
   *
   * @return yyyy-mm-dd
   */
  public static String getLastQuarterFirstDay() {
    Calendar startCalendar = Calendar.getInstance();
    startCalendar.set(Calendar.MONTH, (startCalendar.get(Calendar.MONTH) / 3 - 1) * 3);
    startCalendar.set(Calendar.DAY_OF_MONTH, 1);
    return DateUtils.getDateToStringStart(startCalendar.getTime(), DateFormatConstant.C_YYYY_MM_DD);
  }

  /**
   * 获取上季度最后一天
   *
   * @return yyyy-mm-dd
   */
  public static String getLastQuarterEndDay() {
    Calendar endCalendar = Calendar.getInstance();
    endCalendar.set(Calendar.MONTH, (endCalendar.get(Calendar.MONTH) / 3 - 1) * 3 + 2);
    endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
    return DateUtils.getDateToStringStart(endCalendar.getTime(), DateFormatConstant.C_YYYY_MM_DD);
  }

  /**
   * 去年本季度开始日期
   *
   * @return yyyy-mm-dd
   */
  public static String getLastYearQuarterFirstDay() {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Calendar c = Calendar.getInstance();
    c.setTime(new Date());
    c.add(Calendar.YEAR, -1);
    LocalDate inputDate =
        LocalDate.parse(getDateToString(c.getTime(), DateFormatConstant.C_YYYY_MM_DD));
    LocalDate localDate =
        LocalDate.of(inputDate.getYear(), inputDate.getMonth().firstMonthOfQuarter(), 1);
    return localDate.toString();
  }

  /**
   * 去年本季度结束日期
   *
   * @return yyyy-mm-dd
   */
  public static String getLastYearQuarterEndDay() {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Calendar c = Calendar.getInstance();
    c.setTime(new Date());
    c.add(Calendar.YEAR, -1);
    LocalDate inputDate =
        LocalDate.parse(getDateToString(c.getTime(), DateFormatConstant.C_YYYY_MM_DD));
    Month month = inputDate.getMonth();
    Month firstMonthOfQuarter = month.firstMonthOfQuarter();
    Month endMonthOfQuarter = Month.of(firstMonthOfQuarter.getValue() + 2);
    LocalDate localDate =
        LocalDate.of(
            inputDate.getYear(),
            endMonthOfQuarter,
            endMonthOfQuarter.length(inputDate.isLeapYear()));
    return localDate.toString();
  }

  /**
   * 获取当前时间，年份第一天
   *
   * @return yyyy-mm-dd
   */
  public static String getThisYearFirstDay() {
    return LocalDate.now().plusYears(0).with(TemporalAdjusters.firstDayOfYear()).toString();
  }

  /**
   * 获取当前时间，年份最后一天
   *
   * @return yyyy-mm-dd
   */
  public static String getThisYearEndDay() {
    return LocalDate.now().plusYears(0).with(TemporalAdjusters.lastDayOfYear()).toString();
  }

  /**
   * 获取去年的第一天
   *
   * @return String
   */
  public static String getLastYearFirstDay() {
    return LocalDate.now().plusYears(-1).with(TemporalAdjusters.firstDayOfYear()).toString();
  }

  /**
   * 获取去年的最后一天 DateUtils
   *
   * @return String
   */
  public static String getLastYearEndDay() {
    return LocalDate.now().plusYears(-1).with(TemporalAdjusters.lastDayOfYear()).toString();
  }

  /**
   * 获取当前小时(24小时制)
   *
   * @return int
   */
  public static int getCurrentHour() {
    Calendar calendar = Calendar.getInstance();
    return calendar.get(Calendar.HOUR_OF_DAY);
  }

  /**
   * 获取当前(月份)日期
   *
   * @return int
   */
  public static int getCurrentDayOfMonth() {
    Calendar calendar = Calendar.getInstance();
    return calendar.get(Calendar.DAY_OF_MONTH);
  }

  /**
   * 获取当前(星期)日期(星期一为第一天)
   *
   * @return int
   */
  public static int getCurrentDayOfWeek() {
    Calendar calendar = Calendar.getInstance();
    int day = calendar.get(Calendar.DAY_OF_WEEK);
    if (day == 1) {
      return 7;
    } else {
      return (day - 1);
    }
  }

  /**
   * 获取当前月份（年）
   *
   * @return int
   */
  private static int getCurrentMonthOfYear() {
    Calendar calendar = Calendar.getInstance();
    return calendar.get(Calendar.MONTH) + 1;
  }

  /**
   * 获取本月所在季度的月份
   *
   * @return int
   */
  public static int getCurrentMonthOfQuarter() {
    int month = getCurrentMonthOfYear();
    int qm = month % 3;
    if (qm == 0) {
      qm = 3;
    }
    return qm;
  }

  /**
   * 获取日期对象
   *
   * @param date yyyy-MM-dd
   * @return Date
   */
  public static Date getDate(String date) throws Exception {
    // 设置日期格式
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    return df.parse(date);
  }

  /**
   * 获取日期对象
   *
   * @param dateTime 格式为 yyyy-MM-dd
   * @return Date
   * @throws Exception
   */
  public static Date getDateTime(String dateTime) throws Exception {
    // 设置日期格式
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return df.parse(dateTime);
  }

  /**
   * 获取当前日期，格式：yyyy-MM-dd
   *
   * @return String
   */
  public static String getCurrentDate(String format) {
    // 设置日期格式
    SimpleDateFormat df = new SimpleDateFormat(format);
    return df.format(new Date());
  }

  /**
   * 获取当前时间，格式：yyyy-MM-dd HH:mm:ss
   *
   * @return String
   */
  public static String getCurrentTime() {
    // 设置日期格式
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return df.format(new Date());
  }

  /**
   * 得到n个月之后的月份
   *
   * @param cnt 参数
   * @return String
   */
  public static String getAfterMonth(int cnt) {

    // java.util包
    Calendar canlendar = Calendar.getInstance();

    // 日期减 如果不够减会将月变动
    canlendar.add(Calendar.MONTH, cnt);
    Date date = canlendar.getTime();
    SimpleDateFormat sdfd = new SimpleDateFormat("yyyyMM");
    return sdfd.format(date);
  }

  /**
   * 得到n天之后的日期
   *
   * @param date 日期
   * @param cnt 参数第几天
   * @return String
   * @throws Exception
   */
  public static String getAfterMonthDate(String date, int cnt) throws Exception {
    SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd");
    Date inDate = sdfd.parse(date);

    // java.util包
    Calendar canlendar = Calendar.getInstance();
    canlendar.setTime(inDate);
    canlendar.add(Calendar.MONTH, cnt);
    Date outDate = canlendar.getTime();

    return sdfd.format(outDate);
  }

  /**
   * 得到n天之后的日期
   *
   * @param date 日期
   * @param days n天之后
   * @return
   * @throws Exception
   */
  public static String getAfterDayDate(String date, int days) throws Exception {
    SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd");
    Date inDate = sdfd.parse(date);

    // java.util包
    Calendar canlendar = Calendar.getInstance();
    canlendar.setTime(inDate);

    // 日期减 如果不够减会将月变动
    canlendar.add(Calendar.DATE, days);
    Date outDate = canlendar.getTime();
    return sdfd.format(outDate);
  }

  /**
   * 得到n天之后的时间
   *
   * @param time 指定的开始时间
   * @param days n 天之后
   * @return String
   * @throws Exception 可能出现的异常
   */
  public static String getAfterDayTime(String time, int days) throws Exception {
    SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date inDate = sdfd.parse(time);

    // java.util包
    Calendar canlendar = Calendar.getInstance();
    canlendar.setTime(inDate);

    // 日期减 如果不够减会将月变动
    canlendar.add(Calendar.DATE, days);
    Date outDate = canlendar.getTime();
    return sdfd.format(outDate);
  }

  /**
   * 得到小时之后的时间
   *
   * @param hours 参数几小时
   * @return String
   */
  public static String getAfterHourTime(String time, int hours) throws Exception {
    SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date inDate = sdfd.parse(time);

    // java.util包
    Calendar canlendar = Calendar.getInstance();
    canlendar.setTime(inDate);

    // 日期减 如果不够减会将月变动
    canlendar.add(Calendar.HOUR_OF_DAY, hours);
    Date outDate = canlendar.getTime();
    return sdfd.format(outDate);
  }

  /**
   * 两个时间相差多少年
   *
   * @param startTime 开始时间
   * @param endTime 结束时间
   * @return String
   */
  public static int getDiffYear(String startTime, String endTime) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
    try {
      return (int)
          (((fmt.parse(endTime).getTime() - fmt.parse(startTime).getTime()) / (1000 * 60 * 60 * 24))
              / 365);
    } catch (Exception e) {
      // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
      return 0;
    }
  }

  /**
   * 获取开始时间和结束时间之间相差的小时
   *
   * @param startTime 开始时间，格式：yyyy-MM-dd HH:mm:ss
   * @param endTime 结束时间，格式：yyyy-MM-dd HH:mm:ss
   * @return int
   */
  public static int getDiffDays(String startTime, String endTime) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {
      return (int)
          ((fmt.parse(endTime).getTime() - fmt.parse(startTime).getTime()) / (1000 * 60 * 60 * 24));
    } catch (Exception e) {
      // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
      return 0;
    }
  }

  /**
   * 获取开始时间和结束时间之间相差的小时
   *
   * @param startTime 开始时间，格式：yyyy-MM-dd HH:mm:ss
   * @param endTime 结束时间，格式：yyyy-MM-dd HH:mm:ss
   * @return long
   */
  public static long getDiffHour(String startTime, String endTime) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {
      // long aa=0;
      return (fmt.parse(endTime).getTime() - fmt.parse(startTime).getTime()) / (1000 * 60 * 60);
    } catch (Exception e) {
      // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
      return 0;
    }
  }

  /**
   *
   * <li>功能描述：时间相减得到天数
   *
   * @param beginDateStr 开始时间
   * @param endDateStr 结束时间
   * @return long
   * @author Administrator
   */
  public static long getDaySub(String beginDateStr, String endDateStr) {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    Date beginDate = null;
    Date endDate = null;

    try {
      beginDate = format.parse(beginDateStr);
      endDate = format.parse(endDateStr);
    } catch (ParseException e) {
      e.printStackTrace();
    }
    return (Objects.requireNonNull(endDate).getTime() - beginDate.getTime())
        / (24 * 60 * 60 * 1000);
  }

  /**
   * 获取日期年份
   *
   * @param date 日期
   * @return int
   */
  public static int getYear(String date) {
    if (StringUtils.isEmpty(date) && (date.length() >= Constants.FOUR)) {
      return 0;
    }
    return Integer.parseInt(date.substring(0, 4));
  }

  /**
   * 获取日期月份
   *
   * @param date yyyy-MM-dd格式
   * @return int
   */
  public static int getMonth(String date) {
    if (StringUtils.isEmpty(date) && date.length() >= Constants.SEVEN) {
      return 0;
    }
    return Integer.parseInt(date.substring(5, 7));
  }

  /**
   * 获取日期所在年份的第几周
   *
   * @param date yyyy-MM-dd格式
   * @return int
   */
  public static int getWeekOfYear(String date) throws Exception {
    if (StringUtils.isEmpty(date)) {
      return 0;
    }
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date inDate = sdf.parse(date);

    // java.util包
    Calendar canlendar = Calendar.getInstance();
    canlendar.setTime(inDate);

    return canlendar.get(Calendar.WEEK_OF_YEAR);
  }

  /**
   * @param year
   * @param week
   * @return String
   */
  public static String getYearWeekFirstDay(int year, int week) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, Calendar.JANUARY, 1);

    // 算出第一周还剩几天 +1是因为1号是1天
    int dayOfWeek = 7 - calendar.get(Calendar.DAY_OF_WEEK) + 1;

    // 周数减去第一周再减去要得到的周
    week = week - 2;
    calendar.add(Calendar.DAY_OF_YEAR, week * 7 + dayOfWeek);
    return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
  }

  /**
   * 获取指定年
   *
   * @param year
   * @param week
   * @return
   */
  public static String getYearWeekLastDay(int year, int week) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, Calendar.JANUARY, 1);

    // 算出第一周还剩几天 +1是因为1号是1天
    int dayOfWeek = 7 - calendar.get(Calendar.DAY_OF_WEEK) + 1;

    // 周数减去第一周再减去要得到的周
    week = week - 2;
    calendar.add(Calendar.DAY_OF_YEAR, week * 7 + dayOfWeek + 6);
    return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime());
  }

  /**
   * 获取日期月份
   *
   * @param month
   * @param cnt
   * @return
   */
  public static int getMonthAdd(int month, int cnt) {
    cnt = cnt % 12;
    int m = month + cnt;
    if (m <= 0) {
      m = m + 12;
    }
    return m;
  }

  /**
   * 将短时间格式字符串转换为时间 yyyy-MM-dd
   *
   * @param strDate 时间
   * @param pattern 时间格式
   * @return
   */
  public static Date strToDate(String strDate, String pattern) {
    SimpleDateFormat formatter = new SimpleDateFormat(pattern);
    ParsePosition pos = new ParsePosition(0);
    return formatter.parse(strDate, pos);
  }

  /**
   * 格式化日期
   *
   * @param date 时间
   * @return Date
   */
  private static Date fomatDate(String date) {
    if (StringUtils.isEmpty(date)) {
      return null;
    }
    try {
      String formatStr = "yyyy-MM-dd";
      if (date.contains(Constants.YEAR)
          && date.contains(Constants.MONTH)
          && date.contains(Constants.DATE)) {
        formatStr = "yyyy年MM月dd日";
      } else if (date.contains(Constants.SPRIT)) {
        formatStr = "yyyy/MM/dd";
      }
      return fomatDate(date, formatStr);
    } catch (Exception e) {
      System.err.println("日期转换出错！" + date);
      return null;
    }
  }

  /**
   * 格式化日期
   *
   * @return
   */
  private static Date fomatTime(String time) {
    if (StringUtils.isEmpty(time)) {
      return null;
    }
    try {
      String formatStr = "yyyy-MM-dd HH:mm:ss";
      if (time.contains("年") && time.contains("月") && time.contains("日")) {
        formatStr = "yyyy年MM月dd日 HH:mm:ss";
      } else if (time.contains(Constants.SPRIT)) {
        formatStr = "yyyy/MM/dd HH:mm:ss";
      }
      return fomatDate(time, formatStr);
    } catch (Exception e) {
      System.err.println("日期时间转换出错！" + time);
      return null;
    }
  }

  /**
   * 格式化日期
   *
   * @return
   */
  private static Date fomatDate(String date, String format) {
    DateFormat fmt = new SimpleDateFormat(format);
    try {
      return fmt.parse(date);
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * 日期比较 ， 如果s > = e 返回true 否则返回false
   *
   * @param s 时间
   * @param e 时间
   * @return
   */
  public static boolean compareTime(String s, String e) {
    if (fomatTime(s) == null || fomatTime(e) == null) {
      return false;
    }
    return Objects.requireNonNull(fomatTime(s)).getTime()
        >= Objects.requireNonNull(fomatTime(e)).getTime();
  }

  /**
   * 日期比较 ， 如果s > = e 返回true 否则返回false
   *
   * @param s 时间
   * @param e 时间
   * @return boolean
   */
  public static boolean compareDate(String s, String e) {
    if (fomatDate(s) == null || fomatDate(e) == null) {
      return false;
    }
    return Objects.requireNonNull(fomatDate(s)).getTime()
        >= Objects.requireNonNull(fomatDate(e)).getTime();
  }

  /**
   * 将时间转换为时间戳
   *
   * @param s 日期
   * @param pattern 日期格式
   * @return
   * @throws ParseException
   */
  public static long dateToStamp(String s, String pattern) throws ParseException {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
    Date date = simpleDateFormat.parse(s);
    return date.getTime();
  }

  /**
   * 毫秒转成小时
   *
   * @param millisecond 时长（单位：毫秒）
   * @return
   */
  public static Long msToHour(Long millisecond) {
    return millisecond == null ? 0 : millisecond / (1000 * 60 * 60);
  }
}
